<template>
  <div class="sql-to-word-page">
    <!-- 页头 -->
    <div class="page-header">
      <h1 class="main-title">SQL三线表导出工具</h1>
      <p class="sub-title">两种用法：①自己输入SQL ②AI生成SQL → 导出普通/三线表</p>
    </div>

    <div class="content-wrapper">
      <!-- 左侧主功能 -->
      <div class="left-section">
        <div class="function-card">
          <!-- 1.手动SQL -->
          <div class="input-section">
            <h3 class="section-title">1.手动输入建表SQL</h3>
            <el-input
              v-model="sqlInput"
              type="textarea"
              :rows="10"
              placeholder="在此粘贴/输入完整的 MySQL 建表语句（可多表）"
              class="sql-textarea"
            />
            <div class="options-section">
              <div class="option-group">
                <label class="option-label">导出表格类型</label>
                <el-select v-model="tableType" class="table-select" placeholder="请选择">
                <el-option  label="三线表" value="threeline" />
                  <el-option label="普通表格" value="normal" />
                  
                </el-select>
              </div>
            </div>
            <el-button
              type="primary"
              size="large"
              class="export-btn"
              :loading="isExporting"
              :disabled="!sqlInput.trim()"
              @click="exportToWord()"
            >
              导出 Word（按上面SQL）
            </el-button>
          </div>

          <div class="divider"></div>

          <!-- 2. AI生成SQL -->
          <div class="generate-section">
            <h3 class="section-title">2.AI生成建表SQL</h3>
            <el-input
              v-model="descInput"
              type="textarea"
              :rows="4"
              placeholder="示例：需要学生、课程、选课三张表... 字段、外键、默认值等要求越清晰越好"
              class="sql-textarea"
            />

            <div class="gen-actions">
              <el-button
                type="success"
                size="large"
                :loading="isGenerating"
                :disabled="!descInput.trim() || isGenerating"
                @click="generateSqlFromDesc"
              >
                开始生成
              </el-button>

           

              <el-button
                size="large"
                :disabled="!generatedSql.trim()"
                @click="copyGenerated"
              >
                复制SQL
              </el-button>

              <el-button
                size="large"
                :disabled="!generatedSql.trim()"
                @click="downloadGenerated"
              >
                下载SQL
              </el-button>
            </div>

            <!-- 流式输出（可编辑） -->
            <div class="sql-output" v-if="generatedSql">
              <h4 class="output-title">AI 生成结果（可编辑后再导出）</h4>
              <el-input
                v-model="generatedSql"
                type="textarea"
                :rows="12"
                class="sql-textarea sql-textarea-dark"
              />

              <div class="quick-export-bar">
                <div class="inline">
                  <span class="option-label small">导出表格类型</span>
                  <el-radio-group v-model="aiTableType" size="small">
                    <el-radio-button label="normal">普通表格</el-radio-button>
                    <el-radio-button selected label="threeline">三线表</el-radio-button>
                  </el-radio-group>
                </div>
                <div class="btns">
                  <el-button type="info" @click="fillUpToManual">填入上方SQL</el-button>
                  <el-button type="primary" @click="exportFromAI" :disabled="!generatedSql.trim()" :loading="isExporting">
                    直接导出（按上面选择）
                  </el-button>
                </div>
              </div>

              <p class="tips">
                * 如输出仍显得拥挤，可点击
                <a href="javascript:void(0)" @click="heuristicFormat">尝试格式化</a>
                （基于分号/关键词的简单整理）。
              </p>
            </div>
          </div>
        </div>
      </div>

      <!-- 右侧示意图 -->
      <div class="right-section">
        <div class="preview-card">
          <h3 class="preview-title">导出样式示意</h3>

          <div class="example-item">
            <h4 class="example-title">普通表格</h4>
            <div class="image-container group bg-gray-50 overflow-hidden relative">
              <el-image
                :src="normalTableImage"
                fit="cover"
                class="card-img w-full h-full"
                :preview-src-list="[normalTableImage]"
                preview-teleported
                :hide-on-click-modal="true"
                :z-index="3000"
                style="width: 100%; height: 150px; object-fit: cover;"
              >
                <template #error>
                  <div class="image-error">
                    <el-icon><Picture /></el-icon>
                    <span>加载失败</span>
                  </div>
                </template>
              </el-image>
            </div>
            <p class="example-desc">适用于一般场景</p>
          </div>

          <div class="example-item">
            <h4 class="example-title">三线表</h4>
            <div class="image-container group bg-gray-50 overflow-hidden relative">
              <el-image
                :src="threeLineTableImage"
                fit="cover"
                class="card-img w-full h-full"
                :preview-src-list="[threeLineTableImage]"
                preview-teleported
                :hide-on-click-modal="true"
                :z-index="3000"
                style="width: 100%; height: 150px; object-fit: cover;"
              >
                <template #error>
                  <div class="image-error">
                    <el-icon><Picture /></el-icon>
                    <span>加载失败</span>
                  </div>
                </template>
              </el-image>
            </div>
            <p class="example-desc">论文/规范常用样式</p>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onBeforeUnmount } from "vue";
import { ElMessage } from "element-plus";
import { Picture } from "@element-plus/icons-vue";
import { generateWord } from "@/api/tools";

// ---------------- 手动 SQL → Word ----------------
const sqlInput = ref("");
const tableType = ref<"normal" | "threeline">("threeline");
const isExporting = ref(false);

// 示例图
import normalTableImg from "@/assets/tools/studenword1.png";
import threeLineTableImg from "@/assets/tools/studenword3.png";
const normalTableImage = ref(normalTableImg);
const threeLineTableImage = ref(threeLineTableImg);

async function exportToWord(sourceSql?: string, type?: "normal" | "threeline") {
  const finalSql = (sourceSql ?? sqlInput.value).trim();
  const finalType = type ?? tableType.value;

  if (!finalSql) {
    ElMessage.warning("没有可导出的 SQL");
    return;
  }

  try {
    isExporting.value = true;
   const res = await generateWord({ sql: finalSql, tableType: "threeline" });

    const ct = String(res.headers?.["content-type"] || "").toLowerCase();
    if (!ct.includes("application/vnd.openxmlformats-officedocument.wordprocessingml.document")) {
      let msg = "";
      try { msg = new TextDecoder("utf-8").decode(res.data as ArrayBuffer); } catch {}
      throw new Error(`生成失败：HTTP ${res.status}，CT=${ct}，详情：${msg}`);
    }
    const cd = res.headers?.["content-disposition"] || "";
    const filename = decodeURIComponent(
      (cd.match(/filename\*?=(?:UTF-8'')?([^;]+)$/i)?.[1] || `SQL文档-${finalType}.docx`).replace(/"/g, "")
    );
    const blob = new Blob([res.data], {
      type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
    });
    downloadBlob(blob, filename);

    ElMessage.success("Word 文件导出成功！");
  } catch (e: any) {
    console.error("导出失败:", e);
    ElMessage.error(e?.message || "导出失败，请检查 SQL 或登录状态");
  } finally {
    isExporting.value = false;
  }
}
function downloadBlob(blob: Blob, filename: string) {
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url;
  a.download = filename;
  document.body.appendChild(a);
  a.click();
  a.remove();
  URL.revokeObjectURL(url);
}






// ---------------- AI 生成 SQL（SSE，使用 fetch 解析器） ----------------
const descInput = ref("");
const generatedSql = ref("");
const aiTableType = ref<"normal" | "threeline">("threeline");
const isGenerating = ref(false);

// fetch-SSE 所需
let abortCtrl: AbortController | null = null;



// 停止
const stopGenerating = () => {
  if (abortCtrl) { abortCtrl.abort(); abortCtrl = null; }
  isGenerating.value = false;
};


onBeforeUnmount(stopGenerating);

/** 复制/下载/填充/导出 */
const copyGenerated = async () => {
  try {
    await navigator.clipboard.writeText(generatedSql.value);
    ElMessage.success("已复制到剪贴板");
  } catch { ElMessage.error("复制失败"); }
};

const downloadGenerated = () => {
  if (!generatedSql.value.trim()) return;
  const blob = new Blob([generatedSql.value], { type: "text/plain;charset=utf-8" });
  downloadBlob(blob, "generated.sql");
};

const fillUpToManual = () => {
  if (!generatedSql.value.trim()) {
    ElMessage.warning("暂无可填充的 SQL"); return;
  }
  sqlInput.value = generatedSql.value;
  ElMessage.success("已填入到上方 SQL 输入框");
};

const exportFromAI = () => {
  if (!generatedSql.value.trim()) {
    ElMessage.warning("AI 结果为空"); return;
  }
  exportToWord(generatedSql.value, aiTableType.value);
};

/** 简单“格式化”，在后端暂未保留换行时可用 */
const heuristicFormat = () => {
  if (!generatedSql.value.trim()) return;
  let s = generatedSql.value;

  // 尝试恢复转义换行
  s = s.replace(/\\r\\n/g, "\n").replace(/\\n/g, "\n");

  // 以分号为单元拆分
  const parts = s
    .split(/;\s*/g)
    .map(p => p.trim())
    .filter(Boolean)
    .map(p => (p.endsWith(";") ? p : p + ";"));

  const kw = ["CREATE TABLE", "PRIMARY KEY", "FOREIGN KEY", "REFERENCES", "COMMENT", "NOT NULL", "DEFAULT"];
  const re = new RegExp(`\\b(${kw.join("|")})\\b`, "ig");

  s = parts
    .map(p =>
      p
        .replace(re, "\n$1")
        .replace(/\s*,\s*/g, ",\n  ")
        .replace(/\(\s*/g, "(\n  ")
        .replace(/\s*\)/g, "\n)")
    )
    .join("\n\n");

  generatedSql.value = s.replace(/\n{3,}/g, "\n\n");
};



// 入口：开始生成
const generateSqlFromDesc = async () => {
  if (!descInput.value.trim() || isGenerating.value) return;

  stopGenerating();
  generatedSql.value = "";
  isGenerating.value = true;
  const baseUrl = import.meta.env.VITE_API_BASE;
  const url = `${baseUrl}/tools/api/generate?desc=${encodeURIComponent(descInput.value.trim())}`;
  abortCtrl = new AbortController();

  let seenCreate = false;

  try {
    await startFetchSSE(
      url,
      ({ event, data }) => {
        if (event === "ai_error") {         // 后端报错透传
          ElMessage.error(data || "生成失败");
          stopGenerating();
          return;
        }
        if (event !== "message") return;    // 只处理默认事件

        // data 就是纯内容，不含 "data: "
        let chunk = data || "";

        if (!seenCreate) {
          const i = chunk.indexOf("CREATE");
          if (i === -1) return;
          chunk = chunk.slice(i);
          seenCreate = true;
        }

        generatedSql.value += chunk;        // 直接拼内容
      },
      abortCtrl.signal
    );
  } finally {
    isGenerating.value = false;
  }
};

// fetch 读取 + 解析 SSE：不会把 "data:" 拼进来
async function startFetchSSE(
  url: string,
  onEvent: (e: { event: string; data: string }) => void,
  signal?: AbortSignal
) {
  const resp = await fetch(url, {
    method: "GET",
    headers: { Accept: "text/event-stream" },
    signal,
  });
  if (!resp.ok || !resp.body) throw new Error(`HTTP ${resp.status}`);

  const reader = resp.body.getReader();
  const decoder = new TextDecoder();
  let buffer = "";

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    buffer += decoder.decode(value, { stream: true }).replace(/\r\n/g, "\n");

    let idx: number;
    while ((idx = buffer.indexOf("\n\n")) !== -1) {
      const raw = buffer.slice(0, idx);
      buffer = buffer.slice(idx + 2);

      let event = "message";
      const dataLines: string[] = [];

      for (const line of raw.split("\n")) {
        if (!line || line.startsWith(":")) continue; // 注释/心跳
        if (line.startsWith("event:")) event = line.slice(6).trim();
        else if (line.startsWith("data:")) {
          // 仅取 data 后面的值，去掉一个起始空格但保留原始换行
          dataLines.push(line.slice(10).replace(/^\s/, ""));
        }
      }

      onEvent({ event, data: dataLines.join("\n") });
    }
  }
}




</script>

<style scoped>
.sql-to-word-page { min-height: 100vh; background: #f5f5f5; }
.page-header { text-align: center; padding: 40px 20px 30px; background: #f5f5f5; }
.main-title { font-size: 28px; font-weight: 700; color: #333; margin: 0 0 10px; }
.sub-title { font-size: 14px; color: #666; margin: 0; }
.content-wrapper { display: flex; gap: 20px; padding: 0 20px 40px; max-width: 1400px; margin: 0 auto; }
.left-section { flex: 1; max-width: 900px; }
.right-section { flex: 1; max-width: 500px; }
.function-card, .preview-card { background: #fff; border-radius: 8px; padding: 30px; box-shadow: 0 2px 8px rgba(0,0,0,.1); border: 1px solid #e0e0e0; }

.section-title { font-size: 18px; font-weight: 600; color: #333; margin: 0 0 16px; }
.input-section { margin-bottom: 28px; }
.sql-textarea { width: 100%; }
.sql-textarea :deep(.el-textarea__inner) {
  background: #fafafa !important; border: 1px solid #d9d9d9 !important; color: #333 !important;
  font-family: "Consolas","Monaco","Courier New",monospace; font-size: 14px; line-height: 1.6;
  border-radius: 6px; padding: 12px;
}
.sql-textarea-dark :deep(.el-textarea__inner) {
  background: #0b1020 !important; color: #e6edf3 !important; border: 1px solid #0f1a36 !important;
}
.options-section { margin-top: 16px; }
.option-group { margin-bottom: 18px; }
.option-label { display:block; font-size:14px; color:#333; margin-bottom:8px; font-weight:500; }
.option-label.small { font-size: 12px; color:#666; margin-right: 10px; }
.table-select { width: 100%; }
.table-select :deep(.el-input__wrapper) { background:#fff !important; border:1px solid #d9d9d9 !important; border-radius:6px; }

.export-btn { width: 100%; height: 46px; font-size: 15px; font-weight: 600; }

.divider { height: 1px; background: #eee; margin: 26px 0; }

.generate-section .gen-actions { display: flex; gap: 12px; margin-top: 8px; flex-wrap: wrap; }
.sql-output { margin-top: 14px; }
.output-title { font-size: 14px; color:#333; margin: 0 0 10px; font-weight: 600; }
.quick-export-bar { display:flex; align-items:center; justify-content: space-between; gap: 12px; margin: 12px 0 0; flex-wrap: wrap; }
.quick-export-bar .btns { display: flex; gap: 10px; }

.tips { margin-top: 8px; font-size: 12px; color: #666; }

.preview-title { font-size: 18px; font-weight: 600; color:#333; margin: 0 0 24px; text-align: center; }
.example-item { margin-bottom: 28px; }
.image-container { position: relative; border-radius: 8px; overflow: hidden; background: #fafafa; border: 1px solid #e0e0e0; }
.example-desc { font-size: 12px; color:#666; margin: 8px 0 0; text-align: center; }
.image-error { display:flex; flex-direction:column; align-items:center; justify-content:center; height:150px; color:#999; gap:8px; }
.image-error .el-icon { font-size: 32px; }
</style>
